﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using CodeSmith.Engine;
using System.Data;

using dotNails.CodeGen.Util;

namespace dotNails.CodeGen.Models {
	/// <summary>
	/// Summary description for BaseCodeTemplate.
	/// </summary>
	public class BaseCodeTemplate : CodeTemplate
	{
		#region Constants
		// TODO: Expand this to contain all C# reserved words
		List<string> RESERVED_WORDS = new List<string>() {
										"event",
										"int",
										"class",
										"type",
										"public"
									 };
		#endregion Constants

		#region Properties
		private string _namespace = string.Empty;
		public string Namespace {
			get { return _namespace; }
			set { _namespace = value; }
		}
		
		private StringCollection _interfaces = new StringCollection();
		public StringCollection Interfaces {
			get {return _interfaces;}
		}

		private string _entityBaseClass = string.Empty;
		public string EntityBaseClass { 
			get { return _entityBaseClass; }
			set { _entityBaseClass = value; }
		}

		private string _entityClass = string.Empty;
		public string EntityClass {
			get { return _entityClass; }
			set { _entityClass = value; }
		}

		private string _pluralEntityClass = string.Empty;
		public string PluralEntityClass {
			get {
				if (_pluralEntityClass.Length <= 0)
					_pluralEntityClass = EntityClass + "s"; // Replace with some plural lookup
				return _pluralEntityClass;
			}
			set { _pluralEntityClass = value; }
		}

		private string _entityInstance = string.Empty;
		public string EntityInstance {
			get {
				if (string.IsNullOrEmpty(_entityInstance) && !string.IsNullOrEmpty(EntityClass)) {
					if (IsReservedWord(EntityClass)) {
						_entityInstance = "my" + StringUtil.GetPascalCaseName(EntityClass);
					}
					else {
						_entityInstance = StringUtil.GetCamelCaseName(EntityClass);
					}
				}
				return _entityInstance;
			}
			set { _entityInstance = value; }
		}

		private string _pluralEntityInstance = string.Empty;
		public string PluralEntityInstance {
			get {
				if (_pluralEntityInstance.Length <= 0)
					_pluralEntityInstance = EntityInstance + "s"; // Replace with some plural lookup
				return _pluralEntityInstance;
			}
			set { _pluralEntityInstance = value; }
		}
		#endregion Properties

		public BaseCodeTemplate() {
			
		}

		// TODO: Move to StringUtil
		public string GetPascalCaseName(string value)
		{
			return StringUtil.GetPascalCaseName(value);
		}

		// TODO: Move to StringUtil
		public string GetCamelCaseName(string value)
		{
			return StringUtil.GetCamelCaseName(value);
		}

		// TODO: Move to StringUtil
		public string GetSpacedName(string value)
		{
			StringBuilder spacedName = new StringBuilder();
			
			for (int i = 0; i < value.Length; i++)
			{
				if (i > 0 && i < value.Length - 1 && value.Substring(i, 1).ToUpper() == value.Substring(i, 1))
				{
					spacedName.Append(" ");
				}
				spacedName.Append(value[i]);
			}
			
			return spacedName.ToString();
		}

		public bool IsSystemNullableType(string type) {
			bool result = false;

			switch (type) {
				case "System.String":
				case "object":
				case "System.Data.Linq.Binary":
				case "System.Xml.Linq.XElement":
					result = false;
					break;
				default:
					result = true;
					break;
			}

			return result;
		}

		/// <summary>
		/// This method only gets a default value if the type warrants it
		/// </summary>
		/// <param name="type"></param>
		/// <param name="canBeNull"></param>
		/// <returns></returns>
		public string GetDefaultValue(string type, bool canBeNull) {
			string defaultValue = string.Empty;

			if (!canBeNull) {
				switch (type) {
					case "System.Int16": defaultValue = " = Int16.MinValue"; break;
					case "System.Int32": defaultValue = " = Int32.MinValue"; break;
					case "System.Int64": defaultValue = " = Int64.MinValue"; break;
					default: break;
				}
			}

			return defaultValue;
		}

		/// <summary>
		/// This method will always return a value appropriate to the type, for the simple purpose of altering a value from its system default (to trigger dirty flag) before setting it to null.
		/// </summary>
		/// <param name="type"></param>
		/// <param name="canBeNull"></param>
		/// <returns></returns>
		public string GetValidTypeValueForCSharp(string type) {
			string defaultValue = string.Empty;
		
			switch (type) {
				case "System.Char": defaultValue = @"'~'"; break;
				case "System.String": defaultValue = @"""~~"""; break;
				case "System.Int16": defaultValue = "Int16.MinValue"; break;
				case "System.Int32": defaultValue = "Int32.MinValue"; break;
				case "System.Int64": defaultValue = "Int64.MinValue"; break;
				case "System.DateTime": defaultValue = "DateTime.MinValue"; break;
				case "System.Decimal": defaultValue = "1"; break;
				case "System.Data.Linq.Binary": defaultValue = "new System.Data.Linq.Binary(new byte[] { })"; break;
				//case "System.Boolean": defaultValue = " = something"; break; // booleans are handled separately
				case "System.Byte": defaultValue = "1"; break;
				case "System.Guid": defaultValue = "Guid.Empty"; break;
				default: break;
			}
		
			return defaultValue;
		}
		
		public string GetCSharpVariableType(string type, bool canBeNull) {
			return DbmlUtil.GetCSharpVariableType(type, canBeNull);
		}

		public virtual bool IsReservedWord(string stringToCheck)
		{
			return RESERVED_WORDS.Contains(stringToCheck.Trim().ToLower());
		}

		// TODO: Move to StringUtil
		public string GetLowercaseAbbreviation(string name) {
			// TODO: Make this a little more intelligent (perhaps use first three letters, or figure out
			//  any letters that are capitalized and use all of those letters)
			return name.Substring(0, 1).ToLower();
		}
		
	}
}